﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Text;

namespace V2
{
    /// <summary>
    /// Provides a clean implementation for <see cref="IStreamingSet"/>.
    /// </summary>
    public class Set : IStreamingSet{
        private readonly HashSet< Values > m_Items;

        public Set() { m_Items = new HashSet< Values >(); }
        public bool IsEmpty { get { return m_Items.Count == 0 ; }}

        public void EnqueueChange( IStreamingSet sender, ChangeArgs args ) {
            if( args.Count == 0 ){ throw new ArgumentException("Change notice received, but no change items.");}
            switch( args.ChangeType ) {
                case ChangeType.Add: HandleAddition( sender, args );
                    break;
                case ChangeType.Remove: HandleRemove( sender, args);
                    break;
                case ChangeType.Update:
                case ChangeType.Clear:
                    throw new NotImplementedException();
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        private void HandleAddition(IStreamingSet sender, ChangeArgs args) {
            int previous_count = m_Items.Count;
            int addition_count = args.Count;
            FireChangePending(this, args);

            m_Items.UnionWith( args.AdditionItems );
            if (m_Items.Count != previous_count + addition_count)
            {
                throw new NotImplementedException("Corruption notice should be better. Event notice.");
            }
        }

        private void HandleRemove( IStreamingSet sender, ChangeArgs args ) {
            int previous_count = m_Items.Count;
            int removal_count = args.Count;

            FireChangePending( this, args );
            m_Items.ExceptWith( args.RemovalItems );

            if (m_Items.Count != previous_count - removal_count)
            {
                throw new NotImplementedException("Corruption notice should be better. Event notice.");
            }
        }

        private void FireChangePending(Set set, ChangeArgs args) { if ( CoreRowBinding != null ) CoreRowBinding( set, args ); }
        
        private event ChangeHandler CoreRowBinding;
        public event ChangeHandler RowBinding{ 
            add{
                if( m_Items.Count > 0 ) {
                    List<ChangeItem> list = new List<ChangeItem>();
                    foreach (var item in m_Items) { list.Add(new ChangeItem(item, null)); }
                    value(this, new ChangeArgs(ChangeType.Add, list));
                }
                CoreRowBinding += value;
            }
            remove { CoreRowBinding -= value; }
        }

        //// TODO: fix the transaction garbage
        //private ChangeArgs m_TransactionMutableArgs;
        //private List<ChangeItem> m_MutableArgs;
 
        public void BeginTransaction( ChangeType type ) {
            //if( m_TransactionMutableArgs != null ) throw new NotSupportedException("Transactions must end before new begins");
            //m_MutableArgs = new List<ChangeItem>();
            //m_TransactionMutableArgs = new ChangeArgs( ChangeType.Add, m_MutableArgs );
        }
        public void EndTransaction() {
            //if( m_TransactionMutableArgs == null ) throw new Exception("Attempt to end a transaction that hasn't begun");
            //ChangeArgs args = m_TransactionMutableArgs;
            //m_TransactionMutableArgs = null;
            //FireChangePending( this, m_TransactionMutableArgs );
        }

        //public bool IsInTransaction{ get { return m_TransactionMutableArgs != null; } }
        //public bool InCompatibleTransaction( ChangeType type ) {
        //    return m_TransactionMutableArgs != null && m_TransactionMutableArgs.ChangeType == type;
        //}

        public void Add( Values result_values ) {
            // we should do some crap with transactions, but currently I don't care.
            HandleAddition( null, new ChangeArgs( ChangeType.Add, new ChangeItem( result_values, null ) ) );
        }

        public void Remove( Values result_values ){
            HandleRemove( null, new ChangeArgs( ChangeType.Remove, new ChangeItem( null, result_values ) ));
        }

        public bool Update( Values values ) {
            throw new NotImplementedException();
        }

        public void Clear() {
            List<ChangeItem > change_items = new List< ChangeItem >();
            foreach( var value in m_Items ) {
               change_items.Add( new ChangeItem( null, value )  );
            }
            m_Items.Clear();

            FireChangePending( this, new ChangeArgs( ChangeType.Clear, change_items ) );
        }
    }
}
